#include <alsa/asoundlib.h>
#include <opus/opus.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

// 播放器结构体
struct player {
    snd_pcm_t* device;      // ALSA PCM设备句柄
    int channels;           // 音频通道数
    int sample_rate;        // 采样率
    int duration;           // 音频帧持续时间(毫秒)
    int frames;             // 每个音频帧的采样点数
    OpusDecoder* decoder;   // Opus解码器
    opus_int16* buffer;     // 音频数据缓冲区
};

/**
 * 创建播放器实例
 * @param name        ALSA设备名称，通常为"default"
 * @param sample_rate 采样率
 * @param channels    通道数
 * @param duration    每帧持续时间(毫秒)
 * @return 播放器实例指针，失败返回NULL
 */
struct player* player_create(const char* name, int sample_rate, int channels, int duration)
{
    struct player* player = malloc(sizeof(struct player));
    if (!player)
    {
        return NULL;
    }

    player->channels = channels;
    player->sample_rate = sample_rate;
    player->duration = duration;

    // 打开ALSA播放设备
    int error = snd_pcm_open(&player->device, name, SND_PCM_STREAM_PLAYBACK, 0);
    if (error < 0)
    {
        fprintf(stderr, "open %s failed: %s\n", name, snd_strerror(error));
        free(player);
        return NULL;
    }

    // 设置PCM设备参数
    error = snd_pcm_set_params(player->device,
                            SND_PCM_FORMAT_S16_LE,
                            SND_PCM_ACCESS_RW_INTERLEAVED,
                            player->channels,
                            player->sample_rate,
                            1,
                            player->duration * 5000);  //增加缓冲区大小防止OVERRUN
    if (error < 0) {
        fprintf(stderr, "snd_pcm_set_params: %s\n", snd_strerror(error));
        snd_pcm_close(player->device);
        free(player);
        return NULL;
    }

    // 创建Opus解码器
    player->decoder = opus_decoder_create(player->sample_rate, player->channels, &error);
    if (error != OPUS_OK) {
        fprintf(stderr, "opus_decoder_create: %s\n", opus_strerror(error));
        snd_pcm_close(player->device);
        free(player);
        return NULL;
    }

    // 计算每帧的采样点数并分配缓冲区
    player->frames = player->sample_rate * player->duration / 1000;
    player->buffer = malloc(snd_pcm_frames_to_bytes(player->device, player->frames));
    if (!player->buffer) {
        opus_decoder_destroy(player->decoder);
        snd_pcm_close(player->device);
        free(player);
        return NULL;
    }

    return player;
}

/**
 * 销毁播放器实例并释放资源
 * @param player 播放器实例
 */
void player_destroy(struct player *player)
{
    if (player) {
        if (player->buffer) {
            free(player->buffer);
            player->buffer = NULL;
        }
        if (player->device) {
            snd_pcm_close(player->device);
            player->device = NULL;
        }
        if (player->decoder) {
            opus_decoder_destroy(player->decoder);
            player->decoder = NULL;
        }
        free(player);
    }
}

/**
 * 启动播放器
 * @param player 播放器实例
 * @return 成功返回0，失败返回负值
 */
int player_start(struct player *player)
{
    if (!player)
    {
        return -1;
    }

    return snd_pcm_start(player->device);
}

/**
 * 停止播放器
 * @param player 播放器实例
 * @return 成功返回0，失败返回负值
 */
int player_stop(struct player *player)
{
    if (!player)
    {
        return -1;
    }

    return snd_pcm_drain(player->device);
}

/**
 * 播放音频数据
 * @param player 播放器实例
 * @param data   Opus编码的音频数据
 * @param size   数据大小
 * @return 成功返回0，失败返回负值
 */
int play_audio(struct player* player, char* data, size_t size)
{
    if (!player)
    {
        return -1;
    }

    // 使用Opus解码器解码音频数据
    int dec_frames = opus_decode(player->decoder, data, size, player->buffer, player->frames, 0);
    if (dec_frames < 0) {
        fprintf(stderr, "opus_decode: %s\n", opus_strerror(dec_frames));
        return -1;
    }

    // 写入解码后的音频数据到PCM设备
    snd_pcm_sframes_t frames = snd_pcm_writei(player->device, player->buffer, dec_frames);
    if (frames == -EPIPE)
    {
        // 处理XRUN（缓冲区溢出或不足）错误
        if (snd_pcm_recover(player->device, frames, 1) == 0)
        {
            frames = snd_pcm_writei(player->device, player->buffer, dec_frames);
        }
    }
    if (frames < 0) {
        fprintf(stderr, "snd_pcm_writei: %s\n", snd_strerror(frames));
        return -1;
    }

    return 0;
}

// 接收数据的缓冲区
char buffer[4096];

int main()
{
    // 创建UDP套接字
    int sk = socket(AF_INET, SOCK_DGRAM, 0);
    if (sk < 0) {
        perror("socket");
        return EXIT_FAILURE;
    }
    
    // 配置服务器地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 监听所有接口
    server_addr.sin_port = htons(8889);
    
    // 绑定套接字到指定端口
    if (bind(sk, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("bind");
        close(sk);
        return EXIT_FAILURE;
    }

    // 创建播放器实例，采样率24000Hz，单声道，帧时长60ms
    struct player* player = player_create("default", 24000, 1, 60);
    if (!player)
    {
        close(sk);
        return EXIT_FAILURE;
    }

    // 启动播放器
    player_start(player);

    // 主循环：接收并播放音频数据
    while (1) {
        // 清空缓冲区
        memset(buffer, 0, sizeof buffer);

        // 接收UDP数据包
        ssize_t rbytes = recv(sk, buffer, sizeof buffer, 0);
        if (rbytes < 0)
        {
            perror("recv");
            continue;
        }

        printf("recv %d bytes\n", rbytes);

        // 播放接收到的音频数据
        if (play_audio(player, buffer, rbytes) < 0)
        {
            continue;
        }
    }

    // 停止播放并清理资源
    player_stop(player);
    player_destroy(player);
    // 关闭套接字
    close(sk);

    return EXIT_SUCCESS;
}